/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2008, 2009, 2010.

	This file is part of the Maxsi Library.

	Maxsi Library is free software: you can redistribute it and/or modify it
	under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or (at your
	option) any later version.

	Maxsi Library is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
	License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with Maxsi Library. If not, see <http://www.gnu.org/licenses/>.

	Maxsi Library
	A powerful Cross-Platform C++ General Purpose Library that allows you to
	efficiently create high-performance and reliable applications.

	MaxsiCompress.cpp
	Simple functions that allows you to compress and uncompress data using
	various algorithms.

******************************************************************************/

#include "MaxsiLibrary.h"

#ifdef Maxsi_Support_liblzma
#include <lzma.h>
#endif

BeginMaxsiNamespace

#ifdef Maxsi_Support_liblzma

MAXSI_DEFINE_IMPLEMENTATION(MaxsiCompressionAlgorithmliblzma, MaxsiCompressionAlgorithmLZMA, MAXSI_INTERFACE_STATIC);

MaxsiError liblzmaError2MaxsiError(lzma_ret Error)
{
	if ( Error == LZMA_OK ) { return MAXSI_ERROR_SUCCESS; }
	if ( Error == LZMA_STREAM_END ) { return MAXSI_ERROR_END_OF_STREAM; }
	if ( Error == LZMA_NO_CHECK ) { return MAXSI_ERROR_SUCCESS; }
	if ( Error == LZMA_UNSUPPORTED_CHECK ) { return MAXSI_ERROR_SUCCESS; }
	if ( Error == LZMA_GET_CHECK ) { return MAXSI_ERROR_SUCCESS; }
	if ( Error == LZMA_MEM_ERROR ) { return MAXSI_ERROR_MEM_ALLOC_FAIL; }
	if ( Error == LZMA_MEMLIMIT_ERROR ) { return MAXSI_ERROR_MEM_ALLOC_FAIL; }
	if ( Error == LZMA_FORMAT_ERROR ) { return MAXSI_ERROR_NOT_SUPPORTED; }
	if ( Error == LZMA_DATA_ERROR ) { return MAXSI_ERROR_INVALID_INPUT; }
	if ( Error == LZMA_PROG_ERROR ) { return MAXSI_ERROR_INVALID_INPUT; } // Might also mean MAXSI_ERROR_SUCCESS
	if ( Error == LZMA_PROG_ERROR ) { return MAXSI_ERROR_BUGGY_PROGRAMMER; }	

	return MAXSI_ERROR_UNSPECIFIED;
}

size_t MaxsiCompressionAlgorithmliblzma::GetCompressedBound(size_t InSize)
{
	return lzma_stream_buffer_bound(InSize);
}

MaxsiError MaxsiCompressionAlgorithmliblzma::Compress(int Quality, BYTE* Input, size_t InputSize, BYTE* Output, size_t* OutputSize)
{
	size_t		OutputPos	=	0;

	MaxsiError	Result	= liblzmaError2MaxsiError(lzma_easy_buffer_encode(Quality, LZMA_CHECK_NONE, NULL, Input, InputSize, Output, &OutputPos, *OutputSize));

	*OutputSize		=	OutputPos;

	return Result;
}

MaxsiError MaxsiCompressionAlgorithmliblzma::Uncompress(BYTE* Input, size_t InputSize, BYTE* Output, size_t* OutputSize)
{
	uint64_t	MaxAllowedMemoryUsage	=	SIZE_MAX;
	size_t		InputPos					=	0;
	size_t		OutputPos					=	0;

	MaxsiError	Result	=	liblzmaError2MaxsiError(lzma_stream_buffer_decode(&MaxAllowedMemoryUsage, 0, NULL, Input, &InputPos, InputSize, Output, &OutputPos, *OutputSize));

	*OutputSize		=	OutputPos;

	return Result;
}

EndMaxsiNamespace

#endif

